#include common_scripts\utility;
// check if below includes are removable
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;

init()
{
    level.classMap["class0"] = 0;
    level.classMap["class1"] = 1;
    level.classMap["class2"] = 2;
    level.classMap["class3"] = 3;
    level.classMap["class4"] = 4;
    level.classMap["class5"] = 5;
    level.classMap["class6"] = 6;
    level.classMap["class7"] = 7;
    level.classMap["class8"] = 8;
    level.classMap["class9"] = 9;
    level.classMap["class10"] = 10;
    level.classMap["class11"] = 11;
    level.classMap["class12"] = 12;
    level.classMap["class13"] = 13;
    level.classMap["class14"] = 14;

    level.classMap["custom1"] = 0;
    level.classMap["custom2"] = 1;
    level.classMap["custom3"] = 2;
    level.classMap["custom4"] = 3;
    level.classMap["custom5"] = 4;
    level.classMap["custom6"] = 5;
    level.classMap["custom7"] = 6;
    level.classMap["custom8"] = 7;
    level.classMap["custom9"] = 8;
    level.classMap["custom10"] = 9;

    level.classMap["copycat"] = -1;

    /#
    // classes testclients may choose from.
    level.botClasses = [];
    level.botClasses[0] = "class0";
    level.botClasses[1] = "class0";
    level.botClasses[2] = "class0";
    level.botClasses[3] = "class0";
    level.botClasses[4] = "class0";
    #/

    level.defaultClass = "CLASS_ASSAULT";

    level.classTableName = "mp/classTable.csv";

    //precacheShader( "waypoint_bombsquad" );
    precacheShader( "specialty_pistoldeath" );
    precacheShader( "specialty_finalstand" );

    level thread onPlayerConnecting();
}


getClassChoice( response )
{
    assert( isDefined( level.classMap[response] ) );

    return response;
}

getWeaponChoice( response )
{
    tokens = strtok( response, "," );
    if ( tokens.size > 1 )
        return int(tokens[1]);
    else
        return 0;
}


logClassChoice( class, primaryWeapon, specialType, perks )
{
    if ( class == self.lastClass )
        return;

    self logstring( "choseclass: " + class + " weapon: " + primaryWeapon + " special: " + specialType );
    for( i=0; i<perks.size; i++ )
        self logstring( "perk" + i + ": " + perks[i] );

    self.lastClass = class;
}


cac_getWeapon( classIndex, weaponIndex )
{
    return self getPlayerData( "customClasses", classIndex, "weaponSetups", weaponIndex, "weapon" );
}

cac_getWeaponAttachment( classIndex, weaponIndex )
{
    return self getPlayerData( "customClasses", classIndex, "weaponSetups", weaponIndex, "attachment", 0 );
}

cac_getWeaponAttachmentTwo( classIndex, weaponIndex )
{
    return self getPlayerData( "customClasses", classIndex, "weaponSetups", weaponIndex, "attachment", 1 );
}

cac_getWeaponCamo( classIndex, weaponIndex )
{
    return self getPlayerData( "customClasses", classIndex, "weaponSetups", weaponIndex, "camo" );
}

cac_getPerk( classIndex, perkIndex )
{
    return self getPlayerData( "customClasses", classIndex, "perks", perkIndex );
}

cac_getKillstreak( classIndex, streakIndex )
{
    return self getPlayerData( "killstreaks", streakIndex );
}

cac_getDeathstreak( classIndex )
{
    return self getPlayerData( "customClasses", classIndex, "perks", 4 );
}

cac_getOffhand( classIndex )
{
    return self getPlayerData( "customClasses", classIndex, "specialGrenade" );
}



table_getWeapon( tableName, classIndex, weaponIndex )
{
    if ( weaponIndex == 0 )
        return tableLookup( tableName, 0, "loadoutPrimary", classIndex + 1 );
    else
        return tableLookup( tableName, 0, "loadoutSecondary", classIndex + 1 );
}

table_getWeaponAttachment( tableName, classIndex, weaponIndex, attachmentIndex )
{
    tempName = "none";

    if ( weaponIndex == 0 )
    {
        if ( !isDefined( attachmentIndex ) || attachmentIndex == 0 )
            tempName = tableLookup( tableName, 0, "loadoutPrimaryAttachment", classIndex + 1 );
        else
            tempName = tableLookup( tableName, 0, "loadoutPrimaryAttachment2", classIndex + 1 );
    }
    else
    {
        if ( !isDefined( attachmentIndex ) || attachmentIndex == 0 )
            tempName = tableLookup( tableName, 0, "loadoutSecondaryAttachment", classIndex + 1 );
        else
            tempName = tableLookup( tableName, 0, "loadoutSecondaryAttachment2", classIndex + 1 );
    }

    if ( tempName == "" || tempName == "none" )
        return "none";
    else
        return tempName;


}

table_getWeaponCamo( tableName, classIndex, weaponIndex )
{
    if ( weaponIndex == 0 )
        return tableLookup( tableName, 0, "loadoutPrimaryCamo", classIndex + 1 );
    else
        return tableLookup( tableName, 0, "loadoutSecondaryCamo", classIndex + 1 );
}

table_getEquipment( tableName, classIndex, perkIndex )
{
    assert( perkIndex < 5 );
    return tableLookup( tableName, 0, "loadoutEquipment", classIndex + 1 );
}

table_getPerk( tableName, classIndex, perkIndex )
{
    assert( perkIndex < 5 );
    return tableLookup( tableName, 0, "loadoutPerk" + perkIndex, classIndex + 1 );
}

table_getOffhand( tableName, classIndex )
{
    return tableLookup( tableName, 0, "loadoutOffhand", classIndex + 1 );
}

table_getKillstreak( tableName, classIndex, streakIndex )
{
//    return tableLookup( tableName, 0, "loadoutStreak" + streakIndex, classIndex + 1 );
    return ( "none" );
}

table_getDeathstreak( tableName, classIndex )
{
    return tableLookup( tableName, 0, "loadoutDeathstreak", classIndex + 1 );
}

getClassIndex( className )
{
    assert( isDefined( level.classMap[className] ) );

    return level.classMap[className];
}

/*
getPerk( perkIndex )
{
    if( isSubstr( self.pers["class"], "CLASS_CUSTOM" ) )
        return cac_getPerk( self.class_num, perkIndex );
    else
        return table_getPerk( level.classTableName, self.class_num, perkIndex );
}

getWeaponCamo( weaponIndex )
{
    if( isSubstr( self.pers["class"], "CLASS_CUSTOM" ) )
        return cac_getWeaponCamo( self.class_num, weaponIndex );
    else
        return table_getWeaponCamo( level.classTableName, self.class_num, weaponIndex );
}
*/

cloneLoadout()
{
    clonedLoadout = [];

    class = self.curClass;

    if ( class == "copycat" )
        return ( undefined );

    if( isSubstr( class, "custom" ) )
    {
        class_num = getClassIndex( class );

        loadoutPrimaryAttachment2 = "none";
        loadoutSecondaryAttachment2 = "none";

        loadoutPrimary = cac_getWeapon( class_num, 0 );
        loadoutPrimaryAttachment = cac_getWeaponAttachment( class_num, 0 );
        loadoutPrimaryAttachment2 = cac_getWeaponAttachmentTwo( class_num, 0 );
        loadoutPrimaryCamo = cac_getWeaponCamo( class_num, 0 );
        loadoutSecondaryCamo = cac_getWeaponCamo( class_num, 1 );
        loadoutSecondary = cac_getWeapon( class_num, 1 );
        loadoutSecondaryAttachment = cac_getWeaponAttachment( class_num, 1 );
        loadoutSecondaryAttachment2 = cac_getWeaponAttachmentTwo( class_num, 1 );
        loadoutSecondaryCamo = cac_getWeaponCamo( class_num, 1 );
        loadoutEquipment = cac_getPerk( class_num, 0 );
        loadoutPerk1 = cac_getPerk( class_num, 1 );
        loadoutPerk2 = cac_getPerk( class_num, 2 );
        loadoutPerk3 = cac_getPerk( class_num, 3 );
        loadoutOffhand = cac_getOffhand( class_num );
        loadoutDeathStreak = cac_getDeathstreak( class_num );
    }
    else
    {
        class_num = getClassIndex( class );

        loadoutPrimary = table_getWeapon( level.classTableName, class_num, 0 );
        loadoutPrimaryAttachment = table_getWeaponAttachment( level.classTableName, class_num, 0 , 0);
        loadoutPrimaryAttachment2 = table_getWeaponAttachment( level.classTableName, class_num, 0, 1 );
        loadoutPrimaryCamo = table_getWeaponCamo( level.classTableName, class_num, 0 );
        loadoutSecondary = table_getWeapon( level.classTableName, class_num, 1 );
        loadoutSecondaryAttachment = table_getWeaponAttachment( level.classTableName, class_num, 1 , 0);
        loadoutSecondaryAttachment2 = table_getWeaponAttachment( level.classTableName, class_num, 1, 1 );;
        loadoutSecondaryCamo = table_getWeaponCamo( level.classTableName, class_num, 1 );
        loadoutEquipment = table_getEquipment( level.classTableName, class_num, 0 );
        loadoutPerk1 = table_getPerk( level.classTableName, class_num, 1 );
        loadoutPerk2 = table_getPerk( level.classTableName, class_num, 2 );
        loadoutPerk3 = table_getPerk( level.classTableName, class_num, 3 );
        loadoutOffhand = table_getOffhand( level.classTableName, class_num );
        loadoutDeathstreak = table_getDeathstreak( level.classTableName, class_num );
    }

    clonedLoadout["inUse"] = false;
    clonedLoadout["loadoutPrimary"] = loadoutPrimary;
    clonedLoadout["loadoutPrimaryAttachment"] = loadoutPrimaryAttachment;
    clonedLoadout["loadoutPrimaryAttachment2"] = loadoutPrimaryAttachment2;
    clonedLoadout["loadoutPrimaryCamo"] = loadoutPrimaryCamo;
    clonedLoadout["loadoutSecondary"] = loadoutSecondary;
    clonedLoadout["loadoutSecondaryAttachment"] = loadoutSecondaryAttachment;
    clonedLoadout["loadoutSecondaryAttachment2"] = loadoutSecondaryAttachment2;
    clonedLoadout["loadoutSecondaryCamo"] = loadoutSecondaryCamo;
    clonedLoadout["loadoutEquipment"] = loadoutEquipment;
    clonedLoadout["loadoutPerk1"] = loadoutPerk1;
    clonedLoadout["loadoutPerk2"] = loadoutPerk2;
    clonedLoadout["loadoutPerk3"] = loadoutPerk3;
    clonedLoadout["loadoutOffhand"] = loadoutOffhand;

    return ( clonedLoadout );
}

giveLoadout( team, class, allowCopycat )
{
    self takeAllWeapons();

    primaryIndex = 0;

    // initialize specialty array
    self.specialty = [];

    if ( !isDefined( allowCopycat ) )
        allowCopycat = true;

    primaryWeapon = undefined;

    if ( isDefined( self.pers["copyCatLoadout"] ) && self.pers["copyCatLoadout"]["inUse"] && allowCopycat )
    {
        self maps\mp\gametypes\_class::setClass( "copycat" );
        self.class_num = getClassIndex( "copycat" );

        clonedLoadout = self.pers["copyCatLoadout"];

        loadoutPrimary = clonedLoadout["loadoutPrimary"];
        loadoutPrimaryAttachment = clonedLoadout["loadoutPrimaryAttachment"];
        loadoutPrimaryAttachment2 = clonedLoadout["loadoutPrimaryAttachment2"] ;
        loadoutPrimaryCamo = clonedLoadout["loadoutPrimaryCamo"];
        loadoutSecondary = clonedLoadout["loadoutSecondary"];
        loadoutSecondaryAttachment = clonedLoadout["loadoutSecondaryAttachment"];
        loadoutSecondaryAttachment2 = clonedLoadout["loadoutSecondaryAttachment2"];
        loadoutSecondaryCamo = clonedLoadout["loadoutSecondaryCamo"];
        loadoutEquipment = clonedLoadout["loadoutEquipment"];
        loadoutPerk1 = clonedLoadout["loadoutPerk1"];
        loadoutPerk2 = clonedLoadout["loadoutPerk2"];
        loadoutPerk3 = clonedLoadout["loadoutPerk3"];
        loadoutOffhand = clonedLoadout["loadoutOffhand"];
    }
    else if ( isSubstr( class, "custom" ) )
    {
        class_num = getClassIndex( class );
        self.class_num = class_num;

        loadoutPrimary = cac_getWeapon( class_num, 0 );
        loadoutPrimaryAttachment = cac_getWeaponAttachment( class_num, 0 );
        loadoutPrimaryAttachment2 = cac_getWeaponAttachmentTwo( class_num, 0 );
        loadoutPrimaryCamo = cac_getWeaponCamo( class_num, 0 );
        loadoutSecondaryCamo = cac_getWeaponCamo( class_num, 1 );
        loadoutSecondary = cac_getWeapon( class_num, 1 );
        loadoutSecondaryAttachment = cac_getWeaponAttachment( class_num, 1 );
        loadoutSecondaryAttachment2 = cac_getWeaponAttachmentTwo( class_num, 1 );
        loadoutSecondaryCamo = cac_getWeaponCamo( class_num, 1 );
        loadoutEquipment = cac_getPerk( class_num, 0 );
        loadoutPerk1 = cac_getPerk( class_num, 1 );
        loadoutPerk2 = cac_getPerk( class_num, 2 );
        loadoutPerk3 = cac_getPerk( class_num, 3 );
        loadoutOffhand = cac_getOffhand( class_num );
    }
    else
    {
        class_num = getClassIndex( class );
        self.class_num = class_num;

        loadoutPrimary = table_getWeapon( level.classTableName, class_num, 0 );
        loadoutPrimaryAttachment = table_getWeaponAttachment( level.classTableName, class_num, 0 , 0);
        loadoutPrimaryAttachment2 = table_getWeaponAttachment( level.classTableName, class_num, 0, 1 );
        loadoutPrimaryCamo = table_getWeaponCamo( level.classTableName, class_num, 0 );
        loadoutSecondaryCamo = table_getWeaponCamo( level.classTableName, class_num, 1 );
        loadoutSecondary = table_getWeapon( level.classTableName, class_num, 1 );
        loadoutSecondaryAttachment = table_getWeaponAttachment( level.classTableName, class_num, 1 , 0);
        loadoutSecondaryAttachment2 = table_getWeaponAttachment( level.classTableName, class_num, 1, 1 );;
        loadoutSecondaryCamo = table_getWeaponCamo( level.classTableName, class_num, 1 );
        loadoutEquipment = table_getEquipment( level.classTableName, class_num, 0 );
        loadoutPerk1 = table_getPerk( level.classTableName, class_num, 1 );
        loadoutPerk2 = table_getPerk( level.classTableName, class_num, 2 );
        loadoutPerk3 = table_getPerk( level.classTableName, class_num, 3 );
        loadoutOffhand = table_getOffhand( level.classTableName, class_num );
    }

    if ( level.killstreakRewards )
    {
        loadoutKillstreak1 = self getPlayerData( "killstreaks", 0 );
        loadoutKillstreak2 = self getPlayerData( "killstreaks", 1 );
        loadoutKillstreak3 = self getPlayerData( "killstreaks", 2 );
    }
    else
    {
        loadoutKillstreak1 = "none";
        loadoutKillstreak2 = "none";
        loadoutKillstreak3 = "none";
    }

    if ((( loadoutPerk1 == "specialty_onemanarmy" || loadoutPerk1 == "specialty_omaquickchange" ) &&
        ( loadoutPrimaryAttachment == "gl" || loadoutPrimaryAttachment2 == "gl" )) ||

        (( loadoutPerk1 == "specialty_marathon" || loadoutPerk1 == "specialty_fastmantle" ) &&
        ( loadoutPerk3 == "specialty_extendedmelee" || loadoutPerk3 == "specialty_falldamage" ) &&
        ( loadoutSecondaryAttachment == "tactical" || loadoutSecondaryAttachment2 == "tactical" )) ||

        ( loadoutPrimary == "riotshield" && loadoutEquipment == "c4_mp" ))
    {
        loadoutPrimary = "onemanarmy";
        loadoutSecondary = "onemanarmy";
        self maps\mp\perks\_perkfunctions::selectOneManArmyClass();
    }

    loadoutDeathStreak = "specialty_copycat";

    if ( loadoutPerk3 == "specialty_pistoldeath" )
        loadoutPerk3 = "specialty_heartbreaker";
    else if ( loadoutPerk3 == "specialty_laststandoffhand" )
        loadoutPerk3 = "specialty_quieter";

    if ( loadoutSecondaryAttachment == "akimbo" )
        secondaryName = buildWeaponName( loadoutSecondary, loadoutSecondaryAttachment2, "none" );
    else
        secondaryName = buildWeaponName( loadoutSecondary, loadoutSecondaryAttachment, loadoutSecondaryAttachment2 );

    self _giveWeapon( secondaryName, int(tableLookup( "mp/camoTable.csv", 1, loadoutSecondaryCamo, 0 ) ) );

    self.loadoutPrimaryCamo = int(tableLookup( "mp/camoTable.csv", 1, loadoutPrimaryCamo, 0 ));
    self.loadoutPrimary = loadoutPrimary;
    self.loadoutSecondary = loadoutSecondary;
    self.loadoutSecondaryCamo = int(tableLookup( "mp/camoTable.csv", 1, loadoutSecondaryCamo, 0 ));

    self SetOffhandPrimaryClass( "other" );

    // Action Slots
    self _SetActionSlot( 1, "" );
    //self _SetActionSlot( 1, "nightvision" );
    self _SetActionSlot( 3, "altMode" );
    self _SetActionSlot( 4, "" );

    // Perks
    self _clearPerks();
    self _detachAll();

    // these special case giving pistol death have to come before
    // perk loadout to ensure player perk icons arent overwritten
    if ( level.dieHardMode )
        self maps\mp\perks\_perks::givePerk( "specialty_pistoldeath" );

    // only give the deathstreak for the initial spawn for this life.
    if ( loadoutDeathStreak != "specialty_null" && getTime() == self.spawnTime )
    {
        deathVal = int( tableLookup( "mp/perkTable.csv", 1, loadoutDeathStreak, 6 ) );

        if ( self _hasPerk( "specialty_rollover" ) )
            deathVal -= 1;

        if ( self.pers["cur_death_streak"] == deathVal )
        {
            self thread maps\mp\perks\_perks::givePerk( loadoutDeathStreak );
            self thread maps\mp\gametypes\_hud_message::splashNotify( loadoutDeathStreak );
        }
        else if ( self.pers["cur_death_streak"] > deathVal )
        {
            self thread maps\mp\perks\_perks::givePerk( loadoutDeathStreak );
        }
    }

    self loadoutAllPerks( loadoutEquipment, loadoutPerk1, loadoutPerk2, loadoutPerk3 );

    self setKillstreaks( loadoutKillstreak1, loadoutKillstreak2, loadoutKillstreak3 );

    if ( self hasPerk( "specialty_extraammo", true ) && getWeaponClass( secondaryName ) != "weapon_projectile" )
        self giveMaxAmmo( secondaryName );

    // Primary Weapon
    if ( loadoutPrimaryAttachment == "heartbeat" )
        primaryName = buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment2, "none" );
    else if ( loadoutPrimaryAttachment2 == "heartbeat" )
        primaryName = buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment, "none" );
    else
        primaryName = buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment, loadoutPrimaryAttachment2 );

    self _giveWeapon( primaryName, self.loadoutPrimaryCamo );

    // fix changing from a riotshield class to a riotshield class during grace period not giving a shield
    if ( primaryName == "riotshield_mp" && level.inGracePeriod )
        self notify ( "weapon_change", "riotshield_mp" );

    if ( self hasPerk( "specialty_extraammo", true ) )
        self giveMaxAmmo( primaryName );

    self setSpawnWeapon( primaryName );

    primaryTokens = strtok( primaryName, "_" );
    self.pers["primaryWeapon"] = primaryTokens[0];

    // Primary Offhand was given by givePerk (it's your perk1)

    // Secondary Offhand
    offhandSecondaryWeapon = loadoutOffhand + "_mp";
    if ( loadoutOffhand == "flash_grenade" )
        self SetOffhandSecondaryClass( "flash" );
    else
        self SetOffhandSecondaryClass( "smoke" );

    self giveWeapon( offhandSecondaryWeapon );
    if( loadOutOffhand == "smoke_grenade" )
        self setWeaponAmmoClip( offhandSecondaryWeapon, 1 );
    else if( loadOutOffhand == "flash_grenade" )
        self setWeaponAmmoClip( offhandSecondaryWeapon, 2 );
    else if( loadOutOffhand == "concussion_grenade" )
        self setWeaponAmmoClip( offhandSecondaryWeapon, 2 );
    else
        self setWeaponAmmoClip( offhandSecondaryWeapon, 1 );

    primaryWeapon = primaryName;
    self.primaryWeapon = primaryWeapon;
    self.secondaryWeapon = secondaryName;

    self maps\mp\gametypes\_teams::playerModelForWeapon( self.pers["primaryWeapon"], getBaseWeaponName( secondaryName ) );

    self.isSniper = (weaponClass( self.primaryWeapon ) == "sniper");

    self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" );

    // cac specialties that require loop threads
    self maps\mp\perks\_perks::cac_selector();

    self notify ( "changed_kit" );
    self notify ( "giveLoadout" );
}

_detachAll()
{
    if ( isDefined( self.hasRiotShield ) && self.hasRiotShield )
    {
        if ( self.hasRiotShieldEquipped )
        {
            self DetachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" );
            self.hasRiotShieldEquipped = false;
        }
        else
        {
            self DetachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" );
        }

        self.hasRiotShield = false;
    }

    self detachAll();
}

loadoutAllPerks( loadoutEquipment, loadoutPerk1, loadoutPerk2, loadoutPerk3 )
{
    loadoutEquipment = maps\mp\perks\_perks::validatePerk( 1, loadoutEquipment );
    loadoutPerk1 = maps\mp\perks\_perks::validatePerk( 1, loadoutPerk1 );
    loadoutPerk2 = maps\mp\perks\_perks::validatePerk( 2, loadoutPerk2 );
    loadoutPerk3 = maps\mp\perks\_perks::validatePerk( 3, loadoutPerk3 );

    self maps\mp\perks\_perks::givePerk( loadoutEquipment );
    self maps\mp\perks\_perks::givePerk( loadoutPerk1 );
    self maps\mp\perks\_perks::givePerk( loadoutPerk2 );
    self maps\mp\perks\_perks::givePerk( loadoutPerk3 );

    perkUpgrd[0] = tablelookup( "mp/perktable.csv", 1, loadoutPerk1, 8 );
    perkUpgrd[1] = tablelookup( "mp/perktable.csv", 1, loadoutPerk2, 8 );
    perkUpgrd[2] = tablelookup( "mp/perktable.csv", 1, loadoutPerk3, 8 );

    foreach( upgrade in perkUpgrd )
    {
        if ( upgrade == "" || upgrade == "specialty_null" )
            continue;

        if ( self isItemUnlocked( upgrade ) )
            self maps\mp\perks\_perks::givePerk( upgrade );
    }

}

trackRiotShield()
{
    self endon ( "death" );
    self endon ( "disconnect" );

    self.hasRiotShield = self hasWeapon( "riotshield_mp" );
    self.hasRiotShieldEquipped = (self.currentWeaponAtSpawn == "riotshield_mp");

    // note this function must play nice with _detachAll().

    if ( self.hasRiotShield )
    {
        if ( self.hasRiotShieldEquipped )
        {
            self AttachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" );
        }
        else
        {
            self AttachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" );
        }
    }

    for ( ;; )
    {
        self waittill ( "weapon_change", newWeapon );

        if ( newWeapon == "riotshield_mp" )
        {
            // defensive check in case we somehow get an extra "weapon_change"
            if ( self.hasRiotShieldEquipped )
                continue;

            if ( self.hasRiotShield )
                self MoveShieldModel( "weapon_riot_shield_mp", "tag_shield_back", "tag_weapon_left" );
            else
                self AttachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" );

            self.hasRiotShield = true;
            self.hasRiotShieldEquipped = true;
        }
        else if ( (self IsMantling()) && (newWeapon == "none") )
        {
            // Do nothing, we want to keep that weapon on their arm.
        }
        else if ( self.hasRiotShieldEquipped )
        {
            assert( self.hasRiotShield );
            self.hasRiotShield = self hasWeapon( "riotshield_mp" );

            if ( self.hasRiotShield )
                self MoveShieldModel( "weapon_riot_shield_mp", "tag_weapon_left", "tag_shield_back" );
            else
                self DetachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" );

            self.hasRiotShieldEquipped = false;
        }
        else if ( self.hasRiotShield )
        {
            if ( !self hasWeapon( "riotshield_mp" ) )
            {
                // we probably just lost all of our weapons (maybe switched classes)
                self DetachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" );
                self.hasRiotShield = false;
            }
        }
    }
}


tryAttach( placement ) // deprecated; hopefully we won't need to bring this defensive function back
{
    if ( !isDefined( placement ) || placement != "back" )
        tag = "tag_weapon_left";
    else
        tag = "tag_shield_back";

    attachSize = self getAttachSize();

    for ( i = 0; i < attachSize; i++ )
    {
        attachedTag = self getAttachTagName( i );
        if ( attachedTag == tag &&  self getAttachModelName( i ) == "weapon_riot_shield_mp" )
        {
            return;
        }
    }

    self AttachShieldModel( "weapon_riot_shield_mp", tag );
}

tryDetach( placement ) // deprecated; hopefully we won't need to bring this defensive function back
{
    if ( !isDefined( placement ) || placement != "back" )
        tag = "tag_weapon_left";
    else
        tag = "tag_shield_back";


    attachSize = self getAttachSize();

    for ( i = 0; i < attachSize; i++ )
    {
        attachedModel = self getAttachModelName( i );
        if ( attachedModel == "weapon_riot_shield_mp" )
        {
            self DetachShieldModel( attachedModel, tag);
            return;
        }
    }
    return;
}



buildWeaponName( baseName, attachment1, attachment2 )
{
    if ( !isDefined( level.letterToNumber ) )
        level.letterToNumber = makeLettersToNumbers();

    // disable bling when perks are disabled
    if ( getDvarInt ( "scr_game_perks" ) == 0 )
    {
        attachment2 = "none";

        if ( baseName == "onemanarmy" )
            return ( "beretta_mp" );
    }

    weaponName = baseName;
    attachments = [];

    if ( attachment1 != "none" && attachment2 != "none" )
    {
        if ( level.letterToNumber[attachment1[0]] < level.letterToNumber[attachment2[0]] )
        {

            attachments[0] = attachment1;
            attachments[1] = attachment2;

        }
        else if ( level.letterToNumber[attachment1[0]] == level.letterToNumber[attachment2[0]] )
        {
            if ( level.letterToNumber[attachment1[1]] < level.letterToNumber[attachment2[1]] )
            {
                attachments[0] = attachment1;
                attachments[1] = attachment2;
            }
            else
            {
                attachments[0] = attachment2;
                attachments[1] = attachment1;
            }
        }
        else
        {
            attachments[0] = attachment2;
            attachments[1] = attachment1;
        }
    }
    else if ( attachment1 != "none" )
    {
        attachments[0] = attachment1;
    }
    else if ( attachment2 != "none" )
    {
        attachments[0] = attachment2;
    }

    foreach ( attachment in attachments )
    {
        weaponName += "_" + attachment;
    }

    return ( weaponName + "_mp" );
}


makeLettersToNumbers()
{
    array = [];

    array["a"] = 0;
    array["b"] = 1;
    array["c"] = 2;
    array["d"] = 3;
    array["e"] = 4;
    array["f"] = 5;
    array["g"] = 6;
    array["h"] = 7;
    array["i"] = 8;
    array["j"] = 9;
    array["k"] = 10;
    array["l"] = 11;
    array["m"] = 12;
    array["n"] = 13;
    array["o"] = 14;
    array["p"] = 15;
    array["q"] = 16;
    array["r"] = 17;
    array["s"] = 18;
    array["t"] = 19;
    array["u"] = 20;
    array["v"] = 21;
    array["w"] = 22;
    array["x"] = 23;
    array["y"] = 24;
    array["z"] = 25;

    return array;
}

setKillstreaks( streak1, streak2, streak3 )
{
    self.killStreaks = [];

    if ( self _hasPerk( "specialty_hardline" ) )
        modifier = -1;
    else
        modifier = 0;

    /*if ( streak1 == "none" && streak2 == "none" && streak3 == "none" )
    {
        streak1 = "uav";
        streak2 = "precision_airstrike";
        streak3 = "helicopter";
    }*/

    killStreaks = [];

    if ( streak1 != "none" )
    {
        //if ( !level.splitScreen )
            streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak1, 4 ) );
        //else
        //    streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak1, 5 ) );
        killStreaks[streakVal + modifier] = streak1;
    }

    if ( streak2 != "none" )
    {
        //if ( !level.splitScreen )
            streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak2, 4 ) );
        //else
        //    streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak2, 5 ) );
        killStreaks[streakVal + modifier] = streak2;
    }

    if ( streak3 != "none" )
    {
        //if ( !level.splitScreen )
            streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak3, 4 ) );
        //else
        //    streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak3, 5 ) );
        killStreaks[streakVal + modifier] = streak3;
    }

    // foreach doesn't loop through numbers arrays in number order; it loops through the elements in the order
    // they were added.  We'll use this to fix it for now.
    maxVal = 0;
    foreach ( streakVal, streakName in killStreaks )
    {
        if ( streakVal > maxVal )
            maxVal = streakVal;
    }

    for ( streakIndex = 0; streakIndex <= maxVal; streakIndex++ )
    {
        if ( !isDefined( killStreaks[streakIndex] ) )
            continue;

        streakName = killStreaks[streakIndex];

        self.killStreaks[ streakIndex ] = killStreaks[ streakIndex ];
    }
    // end lameness

    // defcon rollover
    maxRollOvers = 10;
    newKillstreaks = self.killstreaks;
    for ( rollOver = 1; rollOver <= maxRollOvers; rollOver++ )
    {
        foreach ( streakVal, streakName in self.killstreaks )
        {
            newKillstreaks[ streakVal + (maxVal*rollOver) ] = streakName + "-rollover" + rollOver;
        }
    }

    self.killstreaks = newKillstreaks;
}


replenishLoadout() // used by ammo hardpoint.
{
    team = self.pers["team"];
    class = self.pers["class"];

    weaponsList = self GetWeaponsListAll();
    for( idx = 0; idx < weaponsList.size; idx++ )
    {
        weapon = weaponsList[idx];

        self giveMaxAmmo( weapon );
        self SetWeaponAmmoClip( weapon, 9999 );

        if ( weapon == "claymore_mp" || weapon == "claymore_detonator_mp" )
            self setWeaponAmmoStock( weapon, 2 );
    }

    if ( self getAmmoCount( level.classGrenades[class]["primary"]["type"] ) < level.classGrenades[class]["primary"]["count"] )
         self SetWeaponAmmoClip( level.classGrenades[class]["primary"]["type"], level.classGrenades[class]["primary"]["count"] );

    if ( self getAmmoCount( level.classGrenades[class]["secondary"]["type"] ) < level.classGrenades[class]["secondary"]["count"] )
         self SetWeaponAmmoClip( level.classGrenades[class]["secondary"]["type"], level.classGrenades[class]["secondary"]["count"] );
}


onPlayerConnecting()
{
    for(;;)
    {
        level waittill( "connected", player );

        if ( !isDefined( player.pers["class"] ) )
        {
            player.pers["class"] = "";
        }
        player.class = player.pers["class"];
        player.lastClass = "";
        player.detectExplosives = false;
        player.bombSquadIcons = [];
        player.bombSquadIds = [];
    }
}


fadeAway( waitDelay, fadeDelay )
{
    wait waitDelay;

    self fadeOverTime( fadeDelay );
    self.alpha = 0;
}


setClass( newClass )
{
    self.curClass = newClass;
}

getPerkForClass( perkSlot, className )
{
    class_num = getClassIndex( className );

    if( isSubstr( className, "custom" ) )
        return cac_getPerk( class_num, perkSlot );
    else
        return table_getPerk( level.classTableName, class_num, perkSlot );
}


classHasPerk( className, perkName )
{
    return( getPerkForClass( 0, className ) == perkName || getPerkForClass( 1, className ) == perkName || getPerkForClass( 2, className ) == perkName );
}